import { loadDict } from "./networkRequest";

/**
 * ObjectService 类
 * 处理单个列的属性和方法
 */
class ObjectService {
  private readonly item: Record<string, any>;

  constructor(item: Record<string, any>) {
    this.item = item;
  }

  setAttr(key: string, value: any): void {
    this.item[key] = value;
  }

  getAttr(key: string): any {
    return this.item[key];
  }

  get(): Record<string, any> {
    return this.item;
  }

  set(config: Record<string, any> = {}): void {
    for (const [key, value] of Object.entries(config)) {
      this.item[key] = value;
    }
  }
}

/**
 * DictService 类
 * 处理字典相关的服务
 */
class DictService {
  private columns: ObjectService;
  private readonly dicts: Record<string, any>;
  private readonly dictData: any[];
  private readonly dataIndex: string;

  constructor(dataIndex: string, dictData: any[], dicts: Record<string, any>, columns: ObjectService) {
    this.dataIndex = dataIndex;
    this.dictData = dictData;
    this.dicts = dicts;
    this.columns = columns;
  }

  /**
   * 返回原始的字典数据
   */
  getRawDictData(): any[] {
    return this.dictData;
  }

  /**
   * 添加字典项
   */
  append(label: string, value: any, extend: Record<string, any> = {}): void {
    this.getRawDictData().push({ label, value, ...extend });
  }

  /**
   * 重新加载字典
   */
  async loadDict(dictConfig: any): Promise<void> {
    this.columns.setAttr("dict", dictConfig);
    await loadDict(this.dicts, { formType: "select", dict: dictConfig, dataIndex: this.dataIndex });
  }
}

/**
 * ColumnService 类
 * 处理列的管理和操作
 */
class ColumnService {
  private columnMap: Map<string, ObjectService>;
  private dictMap: Map<string, DictService>;
  private columns: any[];
  private cascaders: string[];
  private readonly dicts: Record<string, any>;
  private readonly refs: Record<string, any>;
  private readonly strictMode: boolean;

  constructor(
    data: {
      columns: any[];
      cascaders: string[];
      dicts: Record<string, any>;
      refs?: Record<string, any>;
    },
    strictMode: boolean
  ) {
    this.columnMap = new Map<string, ObjectService>();
    this.dictMap = new Map<string, DictService>();
    this.columns = data.columns;
    this.cascaders = data.cascaders;
    this.dicts = data.dicts;
    this.refs = data.refs ?? {};
    this.strictMode = strictMode;

    this.columns.forEach(item => {
      this.columnMap.set(item.dataIndex, new ObjectService(item));
    });

    for (const [dataIndex, dictData] of Object.entries(this.dicts)) {
      const columnService = this.columnMap.get(dataIndex);
      if (columnService) {
        this.dictMap.set(dataIndex, new DictService(dataIndex, dictData as any[], this.dicts, columnService));
      }
    }
  }

  getDialogRefs(refName?: string): any {
    return refName ? this.refs[refName] : this.refs;
  }

  getDictService(dataIndex: string): DictService | undefined {
    return this.dictMap.get(dataIndex);
  }

  get(dataIndex: string): ObjectService | undefined {
    return this.columnMap.get(dataIndex);
  }

  isEmpty(dataIndex: string): boolean {
    return !this.columnMap.has(dataIndex);
  }

  exist(dataIndex: string): boolean {
    return !this.isEmpty(dataIndex);
  }

  async append(item: any, appendStartDataIndex: string | null = null): Promise<boolean> {
    if (this.strictMode && item.dataIndex && this.exist(item.dataIndex)) {
      console.warn(
        `严格模式：columnService.append(item) 参数中未有item.dataIndex属性或者item.dataIndex已存在column.${item.dataIndex}`
      );
      return false;
    }
    if (this.cascaders.includes(item.dataIndex) && item.dict) {
      await loadDict(this.dicts, item);
    }
    this.columns.push(item);
    this.columnMap.set(item.dataIndex, new ObjectService(item));

    if (appendStartDataIndex !== null) {
      let appendIndex = this.columns.map(item => item.dataIndex)?.indexOf(appendStartDataIndex) ?? -1;

      if (appendIndex === -1) {
        return this.append(item, null);
      }

      let sortIndex = 0;
      let appendPosIndex = 0;
      this.columns.forEach(sortItem => {
        if (sortItem.dataIndex === appendStartDataIndex) {
          appendPosIndex = sortIndex;
        } else if (sortItem.dataIndex === item.dataIndex) {
          sortIndex = appendPosIndex + 1;
        }
        sortItem.sortIndex = sortIndex;
        sortIndex += 2;
      });
      this.columns.sort((a, b) => a.sortIndex - b.sortIndex);
    }
    return true;
  }
}

export default ColumnService;
